use std::ops::Add;

#[derive(Debug)]
struct Point<T> {
    x: T,
    y: T,
}

// 重载运算符
// 泛型结构体与特质的结合起来的使用
impl<T> Add for Point<T>
where
    /*
      疑问：这里的Add是啥，特质？
      解答：这里Add就是特质，这里特质是在描述类型，这里描述的是类型T，T必须实现Add特质，这里Add特质是标准库中定义的，这里重载了Add特质中的add方法，所以这里必须实现Add特质中的add方法
      说明：
        1. 当前在where后面声明T类型的写法，等同于impl<T: Add> Add for Point<T>，但前者更为清晰
        2. T类型后声明特质，可理解为对型约束，被称为通用实现
        3. Add特质的Output关联类型，表示add方法返回的类型
     */
    T: Add<Output = T>,
{
    // 这里的Output是实现Add特质里的Output关联类型，在结构体实现特质是必须要声明的，这里声明了，在重载运算符里就可以使用这个名称来声明类型
    type Output = Self;

    // 第一版理解: 为啥返回的Self后面要::加Output这么使用，首先这是个Self是结构体，结构体本身就是一种类型，直接返回是没问题，但与此同时这个是泛型结构体，也就说如果为更好保持规范性一致性，可以用::方式来声明结构体的泛型内容
    // 第二版理解<正解>: 这里的Self::Output是使用使用关联类型，只不过这里的方法重载了（重写了），所以在这里使用::Output来声明类型，源码中Add trait中的add方法是必须实现，所以在结构体实现特质时候必须重新实现
    fn add(self, rhs: Self) -> Self::Output {
        Point {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = Point { x: 3, y: 4 };
    let p = p1 + p2;
    println!("{:?}", p)
}
